package com.xdb.sqlparser.dialect.oracle.parser;

import com.xdb.sqlparser.ast.SQLExpr;
import com.xdb.sqlparser.ast.SQLName;
import com.xdb.sqlparser.dialect.oracle.ast.clause.OracleLobStorageClause;
import com.xdb.sqlparser.dialect.oracle.ast.clause.OraclePartitionByRangeClause;
import com.xdb.sqlparser.dialect.oracle.ast.clause.OracleRangeValuesClause;
import com.xdb.sqlparser.dialect.oracle.ast.clause.OracleStorageClause;
import com.xdb.sqlparser.dialect.oracle.ast.statement.OracleCreateTableStatement;
import com.xdb.sqlparser.dialect.oracle.ast.statement.OracleSelect;
import com.xdb.sqlparser.dialect.oracle.ast.statement.OracleCreateTableStatement.DeferredSegmentCreation;
import com.xdb.sqlparser.dialect.sql99.parser.SQL99CreateTableParser;
import com.xdb.sqlparser.exception.ParserException;
import com.xdb.sqlparser.parser.SQLLexer;
import com.xdb.sqlparser.parser.SQLToken;

public class OracleCreateTableParser extends SQL99CreateTableParser {

	public OracleCreateTableParser(SQLLexer lexer) {
		super(new OracleExprParser(lexer));
	}

	public OracleCreateTableParser(String sql) {
		super(new OracleExprParser(sql));
	}

	protected OracleCreateTableStatement newCreateStatement() {
		return new OracleCreateTableStatement();
	}

	public OracleCreateTableStatement parseCrateTable(boolean acceptCreate) {
		OracleCreateTableStatement stmt = (OracleCreateTableStatement) super.parseCrateTable(acceptCreate);

		for (;;) {
			if (lexer.token() == SQLToken.TABLESPACE) {
				lexer.nextToken();
				stmt.setTablespace(this.exprParser.name());
				continue;
			} else if (identifierEquals("IN_MEMORY_METADATA")) {
				lexer.nextToken();
				stmt.setInMemoryMetadata(true);
				continue;
			} else if (identifierEquals("CURSOR_SPECIFIC_SEGMENT")) {
				lexer.nextToken();
				stmt.setCursorSpecificSegment(true);
				continue;
			} else if (identifierEquals("NOPARALLEL")) {
				lexer.nextToken();
				stmt.setParallel(false);
				continue;
			} else if (lexer.token() == SQLToken.LOGGING) {
				lexer.nextToken();
				stmt.setLogging(Boolean.TRUE);
				continue;
			} else if (lexer.token() == SQLToken.CACHE) {
				lexer.nextToken();
				stmt.setCache(Boolean.TRUE);
				continue;
			} else if (lexer.token() == SQLToken.NOCACHE) {
				lexer.nextToken();
				stmt.setCache(Boolean.FALSE);
				continue;
			} else if (lexer.token() == SQLToken.NOCOMPRESS) {
				lexer.nextToken();
				stmt.setCompress(Boolean.FALSE);
				continue;
			} else if (lexer.token() == SQLToken.ON) {
				lexer.nextToken();
				accept(SQLToken.COMMIT);
				stmt.setOnCommit(true);
				continue;
			} else if (identifierEquals("PRESERVE")) {
				lexer.nextToken();
				acceptIdentifier("ROWS");
				stmt.setPreserveRows(true);
				continue;
			} else if (identifierEquals("STORAGE")) {
				OracleStorageClause storage = ((OracleExprParser) this.exprParser).parseStorage();
				stmt.setStorage(storage);
				continue;
			} else if (identifierEquals("organization")) {
				lexer.nextToken();
				accept(SQLToken.INDEX);
				stmt.setOrganizationIndex(true);
				continue;
			} else if (lexer.token() == SQLToken.PCTFREE) {
				lexer.nextToken();
				stmt.setPtcfree(this.exprParser.expr());
				continue;
			} else if (identifierEquals("PCTUSED")) {
				lexer.nextToken();
				stmt.setPctused(this.exprParser.expr());
				continue;
			} else if (lexer.token() == SQLToken.STORAGE) {
				OracleStorageClause storage = ((OracleExprParser) this.exprParser).parseStorage();
				stmt.setStorage(storage);
				continue;
			} else if (lexer.token() == SQLToken.LOB) {
				OracleLobStorageClause lobStorage = ((OracleExprParser) this.exprParser).parseLobStorage();
				stmt.setLobStorage(lobStorage);
				continue;
			} else if (lexer.token() == SQLToken.INITRANS) {
				lexer.nextToken();
				stmt.setInitrans(this.exprParser.expr());
				continue;
			} else if (lexer.token() == SQLToken.MAXTRANS) {
				lexer.nextToken();
				stmt.setMaxtrans(this.exprParser.expr());
				continue;
			} else if (lexer.token() == SQLToken.SEGMENT) {
				lexer.nextToken();
				accept(SQLToken.CREATION);
				if (lexer.token() == SQLToken.IMMEDIATE) {
					lexer.nextToken();
					stmt.setDeferredSegmentCreation(DeferredSegmentCreation.IMMEDIATE);
				} else {
					accept(SQLToken.DEFERRED);
					stmt.setDeferredSegmentCreation(DeferredSegmentCreation.DEFERRED);
				}
				continue;
			} else if (identifierEquals("PARTITION")) {
				lexer.nextToken();
				accept(SQLToken.BY);

				if (identifierEquals("RANGE")) {
					lexer.nextToken();
					accept(SQLToken.LPAREN);
					OraclePartitionByRangeClause clause = new OraclePartitionByRangeClause();
					for (;;) {
						SQLName column = this.exprParser.name();
						clause.getColumns().add(column);

						if (lexer.token() == SQLToken.COMMA) {
							lexer.nextToken();
							continue;
						}

						break;
					}
					accept(SQLToken.RPAREN);

					if (identifierEquals("INTERVAL")) {
						lexer.nextToken();
						clause.setInterval(this.exprParser.expr());
					}

					if (lexer.token() == SQLToken.STORE) {
						lexer.nextToken();
						accept(SQLToken.IN);
						accept(SQLToken.LPAREN);
						for (;;) {
							SQLName tablespace = this.exprParser.name();
							clause.getStoreIn().add(tablespace);

							if (lexer.token() == SQLToken.COMMA) {
								lexer.nextToken();
								continue;
							}

							break;
						}
						accept(SQLToken.RPAREN);
					}

					accept(SQLToken.LPAREN);

					for (;;) {
						acceptIdentifier("PARTITION");
						OracleRangeValuesClause range = new OracleRangeValuesClause();
						range.setName(this.exprParser.name());

						accept(SQLToken.VALUES);
						acceptIdentifier("LESS");
						acceptIdentifier("THAN");

						accept(SQLToken.LPAREN);
						for (;;) {
							SQLExpr rangeValue = this.exprParser.expr();
							range.getValues().add(rangeValue);

							if (lexer.token() == SQLToken.COMMA) {
								lexer.nextToken();
								continue;
							}

							break;
						}
						accept(SQLToken.RPAREN);

						clause.getRanges().add(range);

						if (lexer.token() == SQLToken.COMMA) {
							lexer.nextToken();
							continue;
						}

						break;
					}

					accept(SQLToken.RPAREN);

					stmt.setPartitioning(clause);
					continue;
				} else {
					throw new ParserException("TODO : " + lexer.token() + " " + lexer.stringVal());
				}
			}
			break;
		}

		if (lexer.token() == SQLToken.AS) {
			lexer.nextToken();

			OracleSelect select = new OracleSelectParser(exprParser).select();
			stmt.setSelect(select);
		}

		return stmt;
	}

}
